﻿using System.Data.Entity.Validation;
using Wabo.Dal.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using EntityFramework.Extensions;

namespace Wabo.Dal.Repository
{
    public class WaboEFModuleRepository : EFBaseRepository,IModuleRepository
    {
        public Module Get(string controllerName)
        {
            try
            {
                return Context.Modules.FirstOrDefault(m => m.controller == controllerName);
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message);
                return null;
            }
        }
        public Module Get(long moduleId)
        {
            try
            {
                return Context.Modules.FirstOrDefault(m => m.id == moduleId);
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message);
                return null;
            }
        }

        public void Remove(Module m)
        {
            try
            {
                Context.Modules.Remove(m);
                Context.SaveChanges();                
            }
            catch (DbEntityValidationException ex)
            {
                Logger.Error(ex.Message);
                throw;
            }
        }

        public void Remove(long moduleId)
        {
            try
            {
                Context.Modules.Remove(Get(moduleId));
                Context.SaveChanges();
            }
            catch (DbEntityValidationException ex)
            {
                Logger.Error(ex.Message);
                throw;
            }
        }

        public void Update(Module m)
        {
            try
            {
                Module original = Get(m.id);
                if (original != null)
                {
                    Context.Entry(original).CurrentValues.SetValues(m);
                    Context.SaveChanges();

                }
            }
            catch (DbEntityValidationException ex)
            {
                Logger.Error(ex.Message);
                throw;
            }
        }

        public void Add(ref Module m)
        {
            try
            {
                Context.Modules.Add(m);
                Context.SaveChanges();
            }
            catch (DbEntityValidationException ex)
            {
                Logger.Error(ex.Message);
                throw;
            }
        }

        public IEnumerable<Module> Modules
        {
            get
            {
                return Context.Modules.OrderBy( m => m.order);
            }
        }

        private bool CheckGroupAccessProperty(Group g, Module m, bool checkRead, bool checkList, bool checkWrite, bool checkDelete)
        {
            try
            {
                if (checkRead)                
                    return m.ModuleAcl.Any(a => a.group_id == g.id && a.access_read);                
                if (checkList)
                    return m.ModuleAcl.Any(a => a.group_id == g.id && a.access_list);
                if (checkWrite)
                    return m.ModuleAcl.Any(a => a.group_id == g.id && a.access_write);
                if (checkDelete)
                    return m.ModuleAcl.Any(a => a.group_id == g.id && a.access_delete);
                return false;
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message);
                throw;
            }
        }

        public bool GroupCanRead(Group grp, Module m)
        {
            return CheckGroupAccessProperty(grp, m, true, false, false, false);
        }

        public bool GroupCanList(Group grp, Module m)
        {
            return CheckGroupAccessProperty(grp, m, false, true, false, false);
        }

        public bool GroupCanWrite(Group grp, Module m)
        {
            return CheckGroupAccessProperty(grp, m, false, false, true, false);
        }

        public bool GroupCanDelete(Group grp, Module m)
        {
            return CheckGroupAccessProperty(grp, m, false, false, false, true );
        }

        public bool UserCanRead(User usr, Module m)
        {
            return usr.UserGroups.Any(g => GroupCanRead(g.Group, m)  );
        }

        public bool UserCanList(User usr, Module m)
        {
            return usr.UserGroups.Any(g => GroupCanList(g.Group, m));
        }

        public bool UserCanWrite(User usr, Module m)
        {
            return usr.UserGroups.Any(g => GroupCanWrite(g.Group, m));
        }

        public bool UserCanDelete(User usr, Module m)
        {
            if (usr == null || m == null)
                return false;

            return usr.UserGroups.Any(g => GroupCanDelete(g.Group, m));
        }

        public void SetModuleGroupPermissions(Group grp, Module m, bool canList, bool canRead, bool canWrite, bool canDelete)
        {
            try
            {
                ModuleAcl original = Context.ModuleAcl.FirstOrDefault(x => x.group_id == grp.id && x.module_id == m.id);
                var acl = new ModuleAcl
                {
                    group_id = grp.id,
                    module_id = m.id,
                    access_list = canList,
                    access_read = canRead,
                    access_write = canWrite,
                    access_delete = canDelete,
                };
                if( original == null )
                {
                    Context.ModuleAcl.Add(acl);
                }
                else
                {
                    acl.id = original.id;
                    Context.Entry(original).CurrentValues.SetValues(acl);                        
                }
                Context.SaveChanges();                    
            }
            catch (DbEntityValidationException ex)
            {
                Logger.Error(ex.Message);
                throw;
            }
        }


        public void RemoveAll()
        {
            try
            {
                Context.ModuleAcl.Delete(a => true);
                Context.Modules.Delete(m => true);
                Context.SaveChanges();
            }
            catch (DbEntityValidationException ex)
            {
                Logger.Error(ex.Message);
                throw;
            }
        }
    }
}
